home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / Level 0 Macintosh 07Aug94 / Memory.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  12.1 KB  |  512 lines  |  [TEXT/KAHL]

  1. /* Memory.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #pragma options(pack_enums)
  25. #include <Memory.h>
  26. #include <Errors.h>
  27. #include <Files.h>
  28. #pragma options(!pack_enums)
  29.  
  30. #include "Memory.h"
  31. #include "MyMalloc.h"
  32.  
  33.  
  34. #define EnableHeapChecking (True)
  35.  
  36. #define MemoryFillPattern (0x81)
  37.  
  38. #if EnableHeapChecking
  39.     #define HEAPCHECK() CheckHeap()
  40. #else
  41.     #define HEAPCHECK() ((void)0)
  42. #endif
  43.  
  44.  
  45. EXECUTE(long NumPtrsAllocated = 0;)
  46. EXECUTE(MyBoolean Initialized = False;)
  47.  
  48. #if MEMDEBUG /* { */
  49.     #define IsANothing (0)
  50.     #define IsAHandle (1)
  51.     #define IsAPointer (2)
  52.     typedef struct StoreRec
  53.         {
  54.             struct StoreRec*    Next;
  55.             void*                            HandPtr; /* whatever it is */
  56.             short                            Type; /* handle or pointer */
  57.             char*                            Tag; /* string for tagging */
  58.         } StoreRec;
  59.     static StoreRec*        TrackList;
  60.     static short                MemDumpFile;
  61.     static MyBoolean        RegisterPointer(char* ThePointer);
  62.     static void                    DeregisterPointer(char* ThePointer);
  63.     static void                    SetUpChecking(void);
  64.     static void                    ShutOffChecking(void);
  65.     static void                    MemPrint(char* Str,...);
  66. #else /* }{ */
  67.     #define RegisterPointer(ThePointer) (True)
  68.     #define DeregisterPointer(ThePointer)
  69.     #define SetUpChecking()
  70.     #define ShutOffChecking()
  71. #endif /* } */
  72.  
  73.  
  74. /* attempt to allocate a pointer */
  75. #if DEBUG
  76.     char*                EepAllocPtr(long Size, char* Tag)
  77. #else
  78.     char*                EepAllocPtr(long Size)
  79. #endif
  80.     {
  81.         char*                        Temp;
  82.  
  83.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  84.         HEAPCHECK();
  85.         ERROR((Size >= 0x00800000 - 16) || (Size < 0),
  86.             PRERR(AllowResume,"AllocPtr:  Requested size is out of range."));
  87. #if !DEBUG
  88.         if ((Size >= 0x00800000 - 16) || (Size < 0))
  89.             {
  90.                 /* this prevents us from crashing in the final version when allocating */
  91.                 /* really big things */
  92.                 return NIL;
  93.             }
  94. #endif
  95.         Temp = (char*)BlockNew(Size);
  96. #if DEBUG
  97.         if (Temp != NIL)
  98.             {
  99.                 if (!RegisterPointer(Temp))
  100.                     {
  101.                         BlockRelease(Temp);
  102.                         return NIL;
  103.                     }
  104.             }
  105.         if (Temp != NIL)
  106.             {
  107.                 long                        Scan;
  108.  
  109.                 for (Scan = 0; Scan < Size; Scan += 1)
  110.                     {
  111.                         Temp[Scan] = MemoryFillPattern;
  112.                     }
  113.             }
  114.         if (Temp != NIL)
  115.             {
  116.                 SetTag(Temp,Tag);
  117.             }
  118.         if (Temp != NIL)
  119.             {
  120.                 NumPtrsAllocated += 1;
  121.             }
  122. #endif
  123.         return Temp;
  124.     }
  125.  
  126.  
  127. /* release pointer and attempt to restore cache */
  128. void            ReleasePtr(char* ThePtr)
  129.     {
  130.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  131.         ERROR(ThePtr==NIL,PRERR(ForceAbort,"ReleasePtr:  Tried to dispose a NIL pointer."));
  132. #if DEBUG
  133.         if (ThePtr != NIL)
  134.             {
  135.                 NumPtrsAllocated -= 1;
  136.             }
  137.         {
  138.             long                        Scan;
  139.             long                        Limit;
  140.  
  141.             Limit = PtrSize(ThePtr);
  142.             for (Scan = 0; Scan < Limit; Scan += 1)
  143.                 {
  144.                     ThePtr[Scan] = MemoryFillPattern;
  145.                 }
  146.         }
  147. #endif
  148.         DeregisterPointer(ThePtr);
  149.         BlockRelease(ThePtr);
  150.         HEAPCHECK();
  151.     }
  152.  
  153.  
  154. long            PtrSize(char* p)
  155.     {
  156.         long        Result;
  157.  
  158.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  159.         CheckPtrExistence(p);
  160.         return BlockSize(p);
  161.     }
  162.  
  163.  
  164. char*        ResizePtr(char* ThePointer, long NewSize)
  165.     {
  166.         void*            NewOne;
  167. #if MEMDEBUG
  168.         StoreRec*            Scan;
  169. #endif
  170.  
  171.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  172.         NewOne = BlockResize(ThePointer,NewSize);
  173. #if MEMDEBUG
  174.         Scan = TrackList;
  175.         while (Scan != NIL)
  176.             {
  177.                 if ((Scan->Type == IsAPointer) && (Scan->HandPtr == ThePointer))
  178.                     {
  179.                         Scan->HandPtr = NewOne;
  180.                         goto SpiffyPoint;
  181.                     }
  182.                 Scan = Scan->Next;
  183.             }
  184.         APRINT(("ResizePtr: Undefined pointer used: %r",ThePointer));
  185.         PRERR(ForceAbort,"ResizePtr:  Undefined pointer used.");
  186. #endif
  187.      SpiffyPoint:
  188.         return (char*)NewOne;
  189.     }
  190.  
  191.  
  192. /* initialize the cache */
  193. MyBoolean    Eep_InitMemory(void)
  194.     {
  195.         long            Count;
  196.         MyBoolean    ReturnValue;
  197.  
  198.         APRINT(("+InitMemory"));
  199.         MaxApplZone();
  200.         ERROR(Initialized,PRERR(ForceAbort,"InitMemory called more than once."));
  201.         for (Count = 4; Count >= 0; Count -= 1)
  202.             {
  203.                 MoreMasters();
  204.             }
  205.         SetUpChecking();
  206.         EXECUTE(Initialized = True;)
  207.         ReturnValue = InitializeMyMalloc();
  208.         APRINT(("-InitMemory"));
  209.         return ReturnValue;
  210.     }
  211.  
  212.  
  213. void            Eep_FlushMemory(void)
  214.     {
  215.         APRINT(("+FlushMemory"));
  216.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  217.         ERROR(NumPtrsAllocated!=0,PRERR(AllowResume,
  218.             "FlushMemory:  Some pointers are still allocated just before quitting."));
  219.         ShutOffChecking();
  220.         EXECUTE(Initialized = False;)
  221.         APRINT(("-FlushMemory"));
  222.     }
  223.  
  224.  
  225. #if MEMDEBUG /* { */
  226.  
  227.  
  228. static MyBoolean        RegisterPointer(char* ThePointer)
  229.     {
  230.         StoreRec*                    Temp;
  231.  
  232.         Temp = (StoreRec*)BlockNew(sizeof(StoreRec));
  233.         if (Temp == NIL)
  234.             {
  235.                 return False;
  236.             }
  237.         Temp->Next = TrackList;
  238.         TrackList = (StoreRec*)Temp;
  239.         Temp->Type = IsAPointer;
  240.         Temp->HandPtr = ThePointer;
  241.         Temp->Tag = NIL;
  242.         return True;
  243.     }
  244.  
  245.  
  246. static void                    DeregisterPointer(char* ThePointer)
  247.     {
  248.         StoreRec*                    Scan;
  249.         StoreRec*                    Lag;
  250.         char*                            Temp;
  251.  
  252.         Scan = TrackList;
  253.         Lag = NIL;
  254.         while ((Scan != NIL) && (Scan->HandPtr != ThePointer))
  255.             {
  256.                 Lag = Scan;
  257.                 Scan = Scan->Next;
  258.             }
  259.         if (Scan == NIL)
  260.             {
  261.                 APRINT(("Deletion of nonexistent pointer %r",ThePointer));
  262.                 PRERR(ForceAbort,"Deletion of nonexistent pointer.");
  263.             }
  264.         if (Scan->Type != IsAPointer)
  265.             {
  266.                 APRINT(("Deletion of pointer of unknown type %r",ThePointer));
  267.                 PRERR(ForceAbort,"Deletion of pointer of unknown type.");
  268.             }
  269.         if (Lag == NIL)
  270.             {
  271.                 Temp = (char*)TrackList;
  272.                 TrackList = Scan->Next;
  273.                 BlockRelease(Temp);
  274.             }
  275.          else
  276.             {
  277.                 Temp = (char*)Lag->Next;
  278.                 Lag->Next = Scan->Next;
  279.                 BlockRelease(Temp);
  280.             }
  281.     }
  282.  
  283.  
  284. void            SetTag(void* TheRef, char* TheTag)
  285.     {
  286.         StoreRec*        Scan;
  287.         short                TagScan;
  288.  
  289.         Scan = TrackList;
  290.         while ((Scan != NIL) && (Scan->HandPtr != TheRef))
  291.             {
  292.                 Scan = Scan->Next;
  293.             }
  294.         if (Scan == NIL)
  295.             {
  296.                 PRERR(ForceAbort,"Handle/Ptr couldn't be found by SetTag.");
  297.             }
  298.          else
  299.             {
  300.                 Scan->Tag = TheTag;
  301.             }
  302.     }
  303.  
  304.  
  305. /* this checks to see if a pointer exists.  as a performance enhancement (since */
  306. /* we search this list constantly) referenced elements are moved to the head */
  307. /* of the list */
  308. void        CheckPtrExistence(void* ThePointer)
  309.     {
  310.         StoreRec*            Scan;
  311.         StoreRec*            Lag;
  312.  
  313.         HEAPCHECK();
  314.         if (ThePointer == NIL)
  315.             {
  316.                 PRERR(ForceAbort,"CheckPtrExistence:  Pointer is NIL");
  317.             }
  318.         Lag = NIL;
  319.         Scan = TrackList;
  320.         while (Scan != NIL)
  321.             {
  322.                 if ((Scan->Type == IsAPointer) && (Scan->HandPtr == ThePointer))
  323.                     {
  324.                         /* found -- and correct */
  325.                         if (Lag != NIL)
  326.                             {
  327.                                 /* if element isn't at the beginning of the list, move it */
  328.                                 /* there. */
  329.                                 Lag->Next = Scan->Next; /* removed from old place */
  330.                                 Scan->Next = TrackList; /* added to beginning */
  331.                                 TrackList = Scan;
  332.                             }
  333.                         return;
  334.                     }
  335.                 Lag = Scan;
  336.                 Scan = Scan->Next;
  337.             }
  338.         APRINT(("Undefined pointer used: %r",ThePointer));
  339.         PRERR(ForceAbort,"Undefined pointer used.");
  340.     }
  341.  
  342.  
  343. static void                    SetUpChecking(void)
  344.     {
  345.         TrackList = NIL;
  346.     }
  347.  
  348.  
  349. static void                    ShutOffChecking(void)
  350.     {
  351.         unsigned char            DumpName[] = {"\p!!MemCheck Still Allocated Dump"};
  352.         StoreRec*                    Scan;
  353.         short                            VRefNum;
  354.  
  355.         CheckHeap();
  356.         FSDelete(DumpName,0);
  357.         ERROR(Create(DumpName,0,AUDITCREATOR,'TEXT') != noErr,
  358.             PRERR(ForceAbort,"Memory's ShutOffChecking couldn't create dump file."));
  359.         ERROR(FSOpen(DumpName,0,&MemDumpFile) != noErr,PRERR(ForceAbort,
  360.             "Memory's ShutOffChecking couldn't open dump file for writing."));
  361.         /* MemPrint("These handles and pointers are still allocated:"); */
  362.         Scan = TrackList;
  363.         while (Scan != NIL)
  364.             {
  365.                 switch (Scan->Type)
  366.                     {
  367.                         case IsAHandle:
  368.                             MemPrint("Handle %x '%t'",Scan->HandPtr,Scan->Tag);
  369.                             break;
  370.                         case IsAPointer:
  371.                             MemPrint("Pointer %x '%t'",Scan->HandPtr,Scan->Tag);
  372.                             break;
  373.                     }
  374.                 Scan = Scan->Next;
  375.             }
  376.         GetVRefNum(MemDumpFile,&VRefNum);
  377.         FSClose(MemDumpFile);
  378.         FlushVol("\p",VRefNum);
  379.     }
  380.  
  381.  
  382. /* some va_args crud for MemPrint */
  383. typedef void *va_list;
  384. #define __va(arg)  &arg + 1
  385. #define va_start(p, arg)  p = __va(arg)
  386. #define va_arg(p, type)  *(* (type **) &p)++
  387. #define va_end(p)
  388.  
  389. /* I lifted this from Audit.c */
  390. /* this prints a string in the same way that printf does.  it accepts these options: */
  391. /* %x = hexadecimal long */
  392. /* %t = C String (text) */
  393. #define BUFSIZE (256)
  394. static void                    MemPrint(char* Str,...)
  395.     {
  396.         va_list                        pa;
  397.         char                            Buffer[BUFSIZE];
  398.         long                            BufPtr;
  399.         static char                Hex[] = "0123456789abcdef";
  400.  
  401.         BufPtr = 0;
  402.         va_start(pa,Str);
  403.         while (*Str != 0)
  404.             {
  405.                 if (*Str == '%')
  406.                     {
  407.                         Str += 1;
  408.                         switch (*Str)
  409.                             {
  410.                                 case 'x':
  411.                                     {
  412.                                         char                        Buf[9];
  413.                                         short                        Count;
  414.                                         unsigned long        Num;
  415.  
  416.                                         Num = va_arg(pa,long);
  417.                                         for (Count = 8; Count >= 1; Count -= 1)
  418.                                             {
  419.                                                 Buf[Count] = Hex[Num & 0x0000000f];
  420.                                                 Num = Num >> 4;
  421.                                             }
  422.                                         Buf[0] = '$';
  423.                                         for (Count = 0; Count < 9; Count += 1)
  424.                                             {
  425.                                                 Buffer[BufPtr++] = Buf[Count];
  426.                                                 ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,
  427.                                                     "MemPrint buffer overrun."));
  428.                                             }
  429.                                     }
  430.                                     break;
  431.                                 case 't':
  432.                                     {
  433.                                         char*        Strp;
  434.  
  435.                                         Strp = va_arg(pa,char*);
  436.                                         while (*Strp != 0)
  437.                                             {
  438.                                                 Buffer[BufPtr++] = *(Strp++);
  439.                                             }
  440.                                         ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,"MemPrint buffer overrun."));
  441.                                     }
  442.                                     break;
  443.                             }
  444.                         Str += 1;
  445.                     }
  446.                  else
  447.                     {
  448.                         Buffer[BufPtr++] = *(Str++);
  449.                         ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,"MemPrint buffer overrun."));
  450.                     }
  451.             }
  452.         Buffer[BufPtr++] = 0x0d;
  453.         FSWrite(MemDumpFile,&BufPtr,Buffer);
  454.     }
  455.  
  456.  
  457. #else /* }{  this next part is "#if !MEMDEBUG" */
  458.  
  459.  
  460. #if DEBUG /* { */
  461.  
  462. #define AlignmentMask (0x03) /* should be 0x03??? */
  463.  
  464. /* this is the DEBUG (but not MEMDEBUG) version */
  465. void        CheckPtrExistence(void* ThePointer)
  466.     {
  467.         static MyBoolean        ZoneIsValid = False;
  468.         static Zone*                Zone;
  469.         static char*                ZoneBeginning;
  470.         char*                                ZoneEnd;
  471.  
  472.         /* check for various signs of a bad pointer.  note that the last two */
  473.         /* won't work if you have more than 64 Megabytes. */
  474.         if (!ZoneIsValid)
  475.             {
  476.                 Zone = GetZone();
  477.                 ZoneIsValid = True;
  478.                 ZoneBeginning = (char*)&(Zone->heapData);
  479.             }
  480.         ZoneEnd = (char*)Zone->bkLim;
  481.         if ((((unsigned long)ThePointer & AlignmentMask) != 0) || (ThePointer == NIL)
  482.             || ((char*)ThePointer < ZoneBeginning) || ((char*)ThePointer >= ZoneEnd))
  483.             {
  484.                 PRERR(ForceAbort,"Undefined/Garbage Pointer used.");
  485.                 CheckHeap();
  486.             }
  487.         /* HEAPCHECK(); */
  488.     }
  489.  
  490. #endif /* } */
  491.  
  492.  
  493. #endif /* } */
  494.  
  495.  
  496. #if DEBUG
  497. void            PRNGCHK(void* ThePointer, void* EffectiveAddress, signed long AccessSize)
  498.     {
  499.         signed long            PSize;
  500.         signed long            Difference;
  501.  
  502.         PSize = PtrSize((char*)ThePointer);
  503.         Difference = (char*)EffectiveAddress - (char*)ThePointer;
  504.         if ((Difference < 0) || (Difference + AccessSize > PSize))
  505.             {
  506.                 APRINT(("PRNGCHK pointer access range error: (%xl..%xl):%xl(+%l)",ThePointer,
  507.                     (char*)ThePointer + PSize - 1,EffectiveAddress,AccessSize));
  508.                 PRERR(ForceAbort,"Pointer access out of range.");
  509.             }
  510.     }
  511. #endif
  512.